package com.andong.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.andong.domain.dto.AdminAuthDTO;
import com.andong.domain.dto.AdminDTO;
import com.andong.domain.dto.UpdatePasswordDTO;
import com.andong.domain.entity.AdminAuth;
import com.andong.domain.pojo.PageResult;
import com.andong.domain.pojo.Result;
import com.andong.domain.vo.AdminListVO;
import com.andong.service.AdminAuthService;
import com.andong.utils.*;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.andong.domain.entity.Admin;
import com.andong.service.AdminService;
import com.andong.mapper.AdminMapper;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

import static com.andong.utils.SystemConstant.*;

/**
* @author 王海云
* @description 针对表【admin(管理员信息表)】的数据库操作Service实现
* @createDate 2024-01-03 18:44:12
*/
@Service
@Slf4j
public class AdminServiceImpl extends ServiceImpl<AdminMapper, Admin>
    implements AdminService{
    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    @Resource
    private AdminMapper adminMapper;
    @Resource
    private AliOSSUtils aliOSSUtils;
    @Resource
    private AliSMSUtils aliSMSUtils;

    @Resource
    private AdminAuthService adminAuthService;

    @Override
    public Result selectById(Long id) {
        // 查询身份信息
        Admin admin = lambdaQuery().eq(Admin::getId, id).one();
        if (BaseContext.getCurrentIdAndIdentity().get(CURRENT_IDENTITY).equals(SUPER_ADMIN)) {
            AdminListVO adminVO = BeanUtil.copyProperties(admin, AdminListVO.class);
            return Result.success(adminVO);
        }
        return Result.success(admin);
    }

    @Override
    public Result updatePasswordByCode(UpdatePasswordDTO dto) throws Exception {
        String phone = dto.getPhone();
        String code = dto.getCode();
        String password = HmacSHA256Utils.calculateHmacSHA256(dto.getPassword());
        Admin admin = getById(dto.getId());
        if (!admin.getPhone().equals(phone)) {
            return Result.error(PHONE_ERROR);
        }
        // 2.从Redis获取缓存的验证码
        String realCode = (String) redisTemplate.opsForValue().get(phone);
        if (!code.equals(realCode)) {
            // 验证码错误 返回错误信息
            return Result.error(CODE_ERROR);
        }
        // 3.验证通过，修改密码
        admin.setPassword(password);
        updateById(admin);
        // 删除缓存的短信验证码
        redisTemplate.delete(phone);
        return Result.success();
    }

    @Override
    public Result updatePasswordByPre(UpdatePasswordDTO dto) throws Exception {
        Long id = dto.getId();
        String prePassword = HmacSHA256Utils.calculateHmacSHA256(dto.getPrePassword());
        String password = HmacSHA256Utils.calculateHmacSHA256(dto.getPassword());
        // 1.从数据库获取管理员信息
        Admin admin = lambdaQuery().eq(Admin::getId, id).one();
        // 2.判断原密码是否正确
        if (!admin.getPassword().equals(prePassword)) {
            return Result.error(PRE_PASSWORD_ERROR);
        }
        // 3.更新密码
        admin.setPassword(password);
        updateById(admin);
        return Result.success();
    }

    @Override
    public PageResult queryList(Integer page, Integer pageSize, String name, Integer gender, LocalDate begin, LocalDate end) {
        // 构造Admin分页器
        Page<Admin> adminPage = new Page<>(page, pageSize);
        // 构造Admin条件查询器, 得到Admin分页查询基本信息结果
        adminPage = lambdaQuery()
                .like(name != null, Admin::getName, name)
                .eq(gender != null, Admin::getGender, gender)
                .ge(begin != null, Admin::getCreateTime, begin)
                .le(end != null, Admin::getCreateTime, end)
                .orderByAsc(Admin::getCreateTime)
                .page(adminPage);
        // 使用stream流的方式对记录中的每一条数据进行处理
        List<Admin> records = adminPage.getRecords();
        // 把自己的数据剔除
        Long id = (Long) BaseContext.getCurrentIdAndIdentity().get(CURRENT_ID);
        records.removeIf(recode -> Objects.equals(recode.getId(), id));
        List<Object> voList = records.stream().map(recode -> {
            Object adminListVO = new AdminListVO();
            BeanUtil.copyProperties(recode, adminListVO);
            return adminListVO;
        }).toList();
        return new PageResult(adminPage.getTotal(), voList);
    }

    @Override
    public void updateImage(String url) {
        // 获取当前用户id
        Long id = (Long) BaseContext.getCurrentIdAndIdentity().get(CURRENT_ID);
        // 获取原图片URL地址
        Admin admin = adminMapper.selectById(id);
        String originalUrl = admin.getImage();
        if (originalUrl.equals(url)) {
            // 图片相同，不执行操作
            return;
        }
        // 更新图片
        admin.setImage(url);
        updateById(admin);
        // 删除原图片
        aliOSSUtils.delete(originalUrl);
    }

    @Override
    public Result updatePhone(String phone, String code) {
        Long id = (Long) BaseContext.getCurrentIdAndIdentity().get(CURRENT_ID);
        // 1.校验验证码
        if (!aliSMSUtils.checkCode(phone, code)) {
            return Result.error(CODE_ERROR);
        }
        // 2.更新手机号
        lambdaUpdate()
            .eq(Admin::getId, id)
            .set(Admin::getPhone, phone)
            .update(getById(id));
        return Result.success();
    }

    @Override
    public Result updateStatus(Long id, Integer status) {
        // 检查参数格式
        if (!ALL_ACCOUNT_STATUS.contains(status)) {
            return Result.error(STATUS_ERROR);
        }
        lambdaUpdate()
            .eq(Admin::getId, id)
            .set(Admin::getStatus, status)
            .update(getById(id));
        // 更新缓存
        redisTemplate.opsForValue().set(ACCOUNT_STATUS + ADMIN + id, status, ACCOUNT_STATUS_EXPIRE, TimeUnit.MINUTES);
        return Result.success();
    }

    @Override
    @Transactional
    public Result insert(AdminDTO dto) throws Exception {
        // 不允许设置超级管理员
        dto.setIsSuperAdmin(0);
        // 1.校验用户名是否存在以及是否合规
        if (!dto.getUsername().startsWith(ADMIN_ACCOUNT_PREFIX)) {
            return Result.error(ACCOUNT_START_WITH_A);
        }
        Admin admin = lambdaQuery()
                .eq(Admin::getUsername, dto.getUsername())
                .one();
        if (Objects.nonNull(admin)) {
            return Result.error(USERNAME_EXIST);
        }
        // 3.校验手机号
        admin = lambdaQuery()
                .eq(Admin::getPhone, dto.getPhone())
                .one();
        if (Objects.nonNull(admin)) {
            return Result.error(PHONE_BINDING);
        }
        // 校验身份证号
        admin = lambdaQuery()
                .eq(Admin::getIdNumber, dto.getIdNumber())
                .one();
        if (Objects.nonNull(admin)) {
            return Result.error(ID_BINDING);
        }

        // 补全基本信息
        dto.setAge(CommonUtils.getAge(dto.getIdNumber()));
        dto.setGender(CommonUtils.getGender(dto.getIdNumber()));
        // 密码加密 管理员默认密码为身份证后六位
        String password = HmacSHA256Utils.calculateHmacSHA256(CommonUtils.getDefaultPassword(dto.getIdNumber()));
        dto.setPassword(password);
        // 保存基本信息
        Admin admin1 = BeanUtil.copyProperties(dto, Admin.class);
        save(admin1);
        // 添加管理员权限信息
        adminAuthService.saveOrModify(new AdminAuthDTO(admin1.getId(), dto.getAuthIds()));
        return Result.success();
    }

    @Override
    @Transactional
    public Result delete(Long id) {
        // 删除头像
        aliOSSUtils.delete(adminMapper.selectById(id).getImage());
        // 1.删除账号
        removeById(id);
        // 2.删除权限信息
        Db.lambdaUpdate(AdminAuth.class)
                .eq(AdminAuth::getAdminId, id)
                .remove();
        // 3.删除缓存的状态信息以及权限信息
        redisTemplate.delete(ACCOUNT_STATUS + ADMIN + id);
        redisTemplate.delete(ADMIN_AUTH + id);
        return Result.success();
    }
}




